<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 5.4.0">


  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">



<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.15.4/css/all.min.css" integrity="sha256-mUZM63G8m73Mcidfrv5E+Y61y7a12O5mW4ezU3bxqW4=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/animate.css@3.1.1/animate.min.css" integrity="sha256-PR7ttpcvz8qrF57fur/yAx1qXMFJeJFiA6pSzWi0OIE=" crossorigin="anonymous">

<script class="next-config" data-name="main" type="application/json">{"hostname":"tallgy.gitee.io","root":"/","images":"/images","scheme":"Muse","darkmode":false,"version":"8.8.0","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12},"copycode":false,"bookmark":{"enable":false,"color":"#222","save":"auto"},"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"stickytabs":false,"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"fadeInDown","post_body":"fadeInDown","coll_header":"fadeInLeft","sidebar":"fadeInUp"}},"prism":false,"i18n":{"placeholder":"搜索...","empty":"没有找到任何搜索结果：${query}","hits_time":"找到 ${hits} 个搜索结果（用时 ${time} 毫秒）","hits":"找到 ${hits} 个搜索结果"}}</script><script src="/js/config.js"></script>
<meta name="description" content="router进阶学习 导航守卫​        正如其名，vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航。这里有很多方式植入路由导航中：全局的，单个路由独享的，或者组件级的。 全局前置守卫​        你可以使用 router.beforeEach 注册一个全局前置守卫： 1234567const router &#x3D; createRouter(&amp;#123; ... &amp;">
<meta property="og:type" content="article">
<meta property="og:title" content="router进阶">
<meta property="og:url" content="http://tallgy.gitee.io/2022/02/10/router/router%E8%BF%9B%E9%98%B6/index.html">
<meta property="og:site_name" content="tallgy&#39;s blog">
<meta property="og:description" content="router进阶学习 导航守卫​        正如其名，vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航。这里有很多方式植入路由导航中：全局的，单个路由独享的，或者组件级的。 全局前置守卫​        你可以使用 router.beforeEach 注册一个全局前置守卫： 1234567const router &#x3D; createRouter(&amp;#123; ... &amp;">
<meta property="og:locale" content="zh_CN">
<meta property="article:published_time" content="2022-02-10T05:51:03.000Z">
<meta property="article:modified_time" content="2023-06-25T08:57:29.323Z">
<meta property="article:author" content="tallgy">
<meta property="article:tag" content="router">
<meta name="twitter:card" content="summary">


<link rel="canonical" href="http://tallgy.gitee.io/2022/02/10/router/router%E8%BF%9B%E9%98%B6/">



<script class="next-config" data-name="page" type="application/json">{"sidebar":"","isHome":false,"isPost":true,"lang":"zh-CN","comments":true,"permalink":"http://tallgy.gitee.io/2022/02/10/router/router%E8%BF%9B%E9%98%B6/","path":"2022/02/10/router/router进阶/","title":"router进阶"}</script>

<script class="next-config" data-name="calendar" type="application/json">""</script>
<title>router进阶 | tallgy's blog</title>
  




  <noscript>
    <link rel="stylesheet" href="/css/noscript.css">
  </noscript>
</head>

<body itemscope itemtype="http://schema.org/WebPage" class="use-motion">
  <div class="headband"></div>

  <main class="main">
    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏" role="button">
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <i class="logo-line"></i>
      <h1 class="site-title">tallgy's blog</h1>
      <i class="logo-line"></i>
    </a>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
    </div>
  </div>
</div>







</div>
        
  
  <div class="toggle sidebar-toggle" role="button">
    <span class="toggle-line"></span>
    <span class="toggle-line"></span>
    <span class="toggle-line"></span>
  </div>

  <aside class="sidebar">

    <div class="sidebar-inner sidebar-nav-active sidebar-toc-active">
      <ul class="sidebar-nav">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <div class="sidebar-panel-container">
        <!--noindex-->
        <div class="post-toc-wrap sidebar-panel">
            <div class="post-toc animated"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#%E5%AF%BC%E8%88%AA%E5%AE%88%E5%8D%AB"><span class="nav-number">1.</span> <span class="nav-text">导航守卫</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%85%A8%E5%B1%80%E5%89%8D%E7%BD%AE%E5%AE%88%E5%8D%AB"><span class="nav-number">1.1.</span> <span class="nav-text">全局前置守卫</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8F%AF%E9%80%89%E5%8F%82%E6%95%B0-next"><span class="nav-number">1.1.1.</span> <span class="nav-text">可选参数 next</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%85%A8%E5%B1%80%E8%A7%A3%E6%9E%90%E5%AE%88%E5%8D%AB"><span class="nav-number">1.2.</span> <span class="nav-text">全局解析守卫</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%85%A8%E5%B1%80%E5%90%8E%E7%BD%AE%E9%92%A9%E5%AD%90"><span class="nav-number">1.3.</span> <span class="nav-text">全局后置钩子</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E8%B7%AF%E7%94%B1%E7%8B%AC%E4%BA%AB%E7%9A%84%E5%AE%88%E5%8D%AB"><span class="nav-number">1.4.</span> <span class="nav-text">路由独享的守卫</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%BB%84%E4%BB%B6%E5%86%85%E7%9A%84%E5%AE%88%E5%8D%AB"><span class="nav-number">1.5.</span> <span class="nav-text">组件内的守卫</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8F%AF%E7%94%A8%E7%9A%84%E9%85%8D%E7%BD%AE-API"><span class="nav-number">1.5.1.</span> <span class="nav-text">可用的配置 API</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E4%BD%BF%E7%94%A8%E7%BB%84%E5%90%88%E5%BC%8F-API"><span class="nav-number">1.5.2.</span> <span class="nav-text">使用组合式 API</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%AE%8C%E6%95%B4%E7%9A%84%E5%AF%BC%E8%88%AA%E8%A7%A3%E6%9E%90%E6%B5%81%E7%A8%8B"><span class="nav-number">1.6.</span> <span class="nav-text">完整的导航解析流程</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E8%B7%AF%E7%94%B1%E5%85%83%E4%BF%A1%E6%81%AF"><span class="nav-number">2.</span> <span class="nav-text">路由元信息</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#TypeScript"><span class="nav-number">2.1.</span> <span class="nav-text">TypeScript</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E6%95%B0%E6%8D%AE%E8%8E%B7%E5%8F%96"><span class="nav-number">3.</span> <span class="nav-text">数据获取</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%AF%BC%E8%88%AA%E5%AE%8C%E6%88%90%E5%90%8E%E8%8E%B7%E5%8F%96%E6%95%B0%E6%8D%AE"><span class="nav-number">3.1.</span> <span class="nav-text">导航完成后获取数据</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%AF%BC%E8%88%AA%E5%AE%8C%E6%88%90%E5%89%8D%E8%8E%B7%E5%8F%96%E6%95%B0%E6%8D%AE"><span class="nav-number">3.2.</span> <span class="nav-text">导航完成前获取数据</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E7%BB%84%E5%90%88%E5%BC%8FAPI"><span class="nav-number">4.</span> <span class="nav-text">组合式API</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%9C%A8-setup-%E4%B8%AD%E8%AE%BF%E9%97%AE%E8%B7%AF%E7%94%B1%E5%92%8C%E5%BD%93%E5%89%8D%E8%B7%AF%E7%94%B1"><span class="nav-number">4.1.</span> <span class="nav-text">在 setup 中访问路由和当前路由</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%AF%BC%E8%88%AA%E5%AE%88%E5%8D%AB-1"><span class="nav-number">4.2.</span> <span class="nav-text">导航守卫</span></a></li></ol></li></ol></div>
        </div>
        <!--/noindex-->

        <div class="site-overview-wrap sidebar-panel">
          <div class="site-author site-overview-item animated" itemprop="author" itemscope itemtype="http://schema.org/Person">
  <p class="site-author-name" itemprop="name">tallgy</p>
  <div class="site-description" itemprop="description">只是一个知识的搬运工</div>
</div>
<div class="site-state-wrap site-overview-item animated">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
        <a href="/archives/">
          <span class="site-state-item-count">107</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
          <a href="/categories/">
        <span class="site-state-item-count">32</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
          <a href="/tags/">
        <span class="site-state-item-count">74</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>



        </div>
      </div>
    </div>
  </aside>
  <div class="sidebar-dimmer"></div>


    </header>

    
  <div class="back-to-top" role="button" aria-label="返回顶部">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>

<noscript>
  <div class="noscript-warning">Theme NexT works best with JavaScript enabled</div>
</noscript>


    <div class="main-inner post posts-expand">


  


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="http://tallgy.gitee.io/2022/02/10/router/router%E8%BF%9B%E9%98%B6/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="tallgy">
      <meta itemprop="description" content="只是一个知识的搬运工">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="tallgy's blog">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          router进阶
        </h1>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>

      <time title="创建时间：2022-02-10 13:51:03" itemprop="dateCreated datePublished" datetime="2022-02-10T13:51:03+08:00">2022-02-10</time>
    </span>
      <span class="post-meta-item">
        <span class="post-meta-item-icon">
          <i class="far fa-calendar-check"></i>
        </span>
        <span class="post-meta-item-text">更新于</span>
        <time title="修改时间：2023-06-25 16:57:29" itemprop="dateModified" datetime="2023-06-25T16:57:29+08:00">2023-06-25</time>
      </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">分类于</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/router/" itemprop="url" rel="index"><span itemprop="name">router</span></a>
        </span>
    </span>

  
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">
        <p> <strong>router进阶学习</strong></p>
<h1 id="导航守卫"><a href="#导航守卫" class="headerlink" title="导航守卫"></a>导航守卫</h1><p>​        正如其名，vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航。这里有很多方式植入路由导航中：全局的，单个路由独享的，或者组件级的。</p>
<h2 id="全局前置守卫"><a href="#全局前置守卫" class="headerlink" title="全局前置守卫"></a>全局前置守卫</h2><p>​        你可以使用 <code>router.beforeEach</code> 注册一个全局前置守卫：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">const router = createRouter(&#123; ... &#125;)</span><br><span class="line"></span><br><span class="line">router.beforeEach((to, from) =&gt; &#123;</span><br><span class="line">  // ...</span><br><span class="line">  // 返回 false 以取消导航</span><br><span class="line">  return false</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<p>​        当一个导航触发时，全局前置守卫按照创建顺序调用。守卫是异步解析执行，此时导航在所有守卫 resolve 完之前一直处于<strong>等待中</strong>。</p>
<p>​        每个守卫方法接收两个参数：</p>
<ul>
<li><strong><code>to</code></strong>: 即将要进入的目标 <a target="_blank" rel="noopener" href="https://router.vuejs.org/zh/api/#routelocationnormalized">用一种标准化的方式</a></li>
<li><strong><code>from</code></strong>: 当前导航正要离开的路由 <a target="_blank" rel="noopener" href="https://router.vuejs.org/zh/api/#routelocationnormalized">用一种标准化的方式</a></li>
</ul>
<p>​        可以返回的值如下:</p>
<ul>
<li><code>false</code>: 取消当前的导航。如果浏览器的 URL 改变了(可能是用户手动或者浏览器后退按钮)，那么 URL 地址会重置到 <code>from</code> 路由对应的地址。</li>
<li>一个<a target="_blank" rel="noopener" href="https://router.vuejs.org/zh/api/#routelocationraw">路由地址</a>: 通过一个路由地址跳转到一个不同的地址，就像你调用 <a target="_blank" rel="noopener" href="https://router.vuejs.org/zh/api/#push"><code>router.push()</code></a> 一样，你可以设置诸如 <code>replace: true</code> 或 <code>name: &#39;home&#39;</code> 之类的配置。当前的导航被中断，然后进行一个新的导航，就和 <code>from</code> 一样。</li>
</ul>
<p>​        如果遇到了意料之外的情况，可能会抛出一个 <code>Error</code>。这会取消导航并且调用 <a target="_blank" rel="noopener" href="https://router.vuejs.org/zh/api/#onerror"><code>router.onError()</code></a> 注册过的回调。</p>
<p>​        如果什么都没有，<code>undefined</code> 或返回 <code>true</code>，<strong>则导航是有效的</strong>，并调用下一个导航守卫</p>
<p>​        以上所有都同 <strong><code>async</code> 函数</strong> 和 Promise 工作方式一样：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">router.beforeEach(async (to, from) =&gt; &#123;</span><br><span class="line">  // canUserAccess() 返回 `true` 或 `false`</span><br><span class="line">  return await canUserAccess(to)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>



<h3 id="可选参数-next"><a href="#可选参数-next" class="headerlink" title="可选参数 next"></a>可选参数 next</h3><p>​        <strong>确保 <code>next</code></strong> 在任何给定的导航守卫中都被<strong>严格调用一次</strong>。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">// BAD</span><br><span class="line">router.beforeEach((to, from, next) =&gt; &#123;</span><br><span class="line">  if (to.name !== &#x27;Login&#x27; &amp;&amp; !isAuthenticated) next(&#123; name: &#x27;Login&#x27; &#125;)</span><br><span class="line">  // 如果用户未能验证身份，则 `next` 会被调用两次</span><br><span class="line">  next()</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">// GOOD</span><br><span class="line">router.beforeEach((to, from, next) =&gt; &#123;</span><br><span class="line">  if (to.name !== &#x27;Login&#x27; &amp;&amp; !isAuthenticated) next(&#123; name: &#x27;Login&#x27; &#125;)</span><br><span class="line">  else next()</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>



<h2 id="全局解析守卫"><a href="#全局解析守卫" class="headerlink" title="全局解析守卫"></a>全局解析守卫</h2><p>​        你可以用 <code>router.beforeResolve</code> 注册一个全局守卫。这和 <code>router.beforeEach</code> 类似，因为它在 <strong>每次导航</strong>时都会触发，但是确保在导航被确认之前，<strong>同时在所有组件内守卫和异步路由组件被解析之后，解析守卫就被正确调用</strong>。这里有一个例子，确保用户可以访问<a target="_blank" rel="noopener" href="https://router.vuejs.org/zh/guide/advanced/meta.html">自定义 meta</a> 属性 <code>requiresCamera</code> 的路由：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">router.beforeResolve(async to =&gt; &#123;</span><br><span class="line">  if (to.meta.requiresCamera) &#123;</span><br><span class="line">    try &#123;</span><br><span class="line">      await askForCameraPermission()</span><br><span class="line">    &#125; catch (error) &#123;</span><br><span class="line">      if (error instanceof NotAllowedError) &#123;</span><br><span class="line">        // ... 处理错误，然后取消导航</span><br><span class="line">        return false</span><br><span class="line">      &#125; else &#123;</span><br><span class="line">        // 意料之外的错误，取消导航并把错误传给全局处理器</span><br><span class="line">        throw error</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<p>​        <code>router.beforeResolve</code> 是获取数据或执行任何其他操作（如果用户无法进入页面时你希望避免执行的操作）的理想位置。</p>
<h2 id="全局后置钩子"><a href="#全局后置钩子" class="headerlink" title="全局后置钩子"></a>全局后置钩子</h2><p>​        你也可以注册全局后置钩子，然而和守卫不同的是，这些钩子不会接受 <code>next</code> 函数也不会改变导航本身：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">router.afterEach((to, from) =&gt; &#123;</span><br><span class="line">  sendToAnalytics(to.fullPath)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<p>​        它们对于分析、更改页面标题、声明页面等辅助功能以及许多其他事情都很有用。</p>
<p>​        它们也反映了 <a target="_blank" rel="noopener" href="https://router.vuejs.org/zh/guide/advanced/navigation-failures.html">navigation failures</a> 作为第三个参数：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">router.afterEach((to, from, failure) =&gt; &#123;</span><br><span class="line">  if (!failure) sendToAnalytics(to.fullPath)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<p>​        <strong>navigation failures 的属性</strong> </p>
<p>​        所有导航失败都会公开<code>to</code>和<code>from</code>属性以反映当前位置以及失败导航的目标位置：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">// trying to access the admin page</span><br><span class="line">router.push(&#x27;/admin&#x27;).then(failure =&gt; &#123;</span><br><span class="line">  if (isNavigationFailure(failure, NavigationFailureType.redirected)) &#123;</span><br><span class="line">    failure.to.path // &#x27;/admin&#x27;</span><br><span class="line">    failure.from.path // &#x27;/&#x27;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>



<h2 id="路由独享的守卫"><a href="#路由独享的守卫" class="headerlink" title="路由独享的守卫"></a>路由独享的守卫</h2><p>​        你可以直接在路由配置上定义 <code>beforeEnter</code> 守卫：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">const routes = [</span><br><span class="line">  &#123;</span><br><span class="line">    path: &#x27;/users/:id&#x27;,</span><br><span class="line">    component: UserDetails,</span><br><span class="line">    beforeEnter: (to, from) =&gt; &#123;</span><br><span class="line">      // reject the navigation</span><br><span class="line">      return false</span><br><span class="line">    &#125;,</span><br><span class="line">  &#125;,</span><br><span class="line">]</span><br></pre></td></tr></table></figure>

<p>​        <code>beforeEnter</code> 守卫 <strong>只在进入路由时触发</strong>，不会在 <code>params</code>、<code>query</code> 或 <code>hash</code> 改变时触发。例如，从 <code>/users/2</code> 进入到 <code>/users/3</code> 或者从 <code>/users/2#info</code> 进入到 <code>/users/2#projects</code>。它们只有在 <strong>从一个不同的</strong> 路由导航时，才会被触发。</p>
<p>​        注意：</p>
<ul>
<li>beforeEnter 是写在routes里面，而不是组件里面。</li>
<li>其次触发时机就是进入路由的时候，但是如果没有离开路由就不会再次触发了。其中对于 参数的变化也是在路由之中的。</li>
<li>return 值的判定就是导航守卫的判定方法。</li>
</ul>
<p>​        你也可以将一个函数数组传递给 <code>beforeEnter</code>，这在为不同的路由重用守卫时很有用：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">function removeQueryParams(to) &#123;</span><br><span class="line">  if (Object.keys(to.query).length)</span><br><span class="line">    return &#123; path: to.path, query: &#123;&#125;, hash: to.hash &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">function removeHash(to) &#123;</span><br><span class="line">  if (to.hash) return &#123; path: to.path, query: to.query, hash: &#x27;&#x27; &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">const routes = [</span><br><span class="line">  &#123;</span><br><span class="line">    path: &#x27;/users/:id&#x27;,</span><br><span class="line">    component: UserDetails,</span><br><span class="line">    beforeEnter: [removeQueryParams, removeHash],</span><br><span class="line">  &#125;,</span><br><span class="line">  &#123;</span><br><span class="line">    path: &#x27;/about&#x27;,</span><br><span class="line">    component: UserDetails,</span><br><span class="line">    beforeEnter: [removeQueryParams],</span><br><span class="line">  &#125;,</span><br><span class="line">]</span><br></pre></td></tr></table></figure>

<p>​        请注意，你也可以通过使用<a target="_blank" rel="noopener" href="https://router.vuejs.org/zh/guide/advanced/meta.html">路径 meta 字段</a>和<a target="_blank" rel="noopener" href="https://router.vuejs.org/zh/guide/advanced/navigation-guards.html#global-before-guards">全局导航守卫</a>来实现类似的行为。</p>
<h2 id="组件内的守卫"><a href="#组件内的守卫" class="headerlink" title="组件内的守卫"></a>组件内的守卫</h2><p>​        最后，你可以在路由组件内直接定义路由导航守卫(传递给路由配置的)</p>
<h3 id="可用的配置-API"><a href="#可用的配置-API" class="headerlink" title="可用的配置 API"></a>可用的配置 API</h3><p>你可以为路由组件添加以下配置：</p>
<ul>
<li><code>beforeRouteEnter</code></li>
<li><code>beforeRouteUpdate</code></li>
<li><code>beforeRouteLeave</code></li>
</ul>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">const UserDetails = &#123;</span><br><span class="line">  template: `...`,</span><br><span class="line">  beforeRouteEnter(to, from) &#123;</span><br><span class="line">    // 在渲染该组件的对应路由被验证前调用</span><br><span class="line">    // 不能获取组件实例 `this` ！</span><br><span class="line">    // 因为当守卫执行时，组件实例还没被创建！</span><br><span class="line">  &#125;,</span><br><span class="line">  beforeRouteUpdate(to, from) &#123;</span><br><span class="line">    // 在当前路由改变，但是该组件被复用时调用</span><br><span class="line">    // 举例来说，对于一个带有动态参数的路径 `/users/:id`，在 `/users/1` 和 `/users/2` 之间跳转的时候，</span><br><span class="line">    // 由于会渲染同样的 `UserDetails` 组件，因此组件实例会被复用。而这个钩子就会在这个情况下被调用。</span><br><span class="line">    // 因为在这种情况发生的时候，组件已经挂载好了，导航守卫可以访问组件实例 `this`</span><br><span class="line">  &#125;,</span><br><span class="line">  beforeRouteLeave(to, from) &#123;</span><br><span class="line">    // 在导航离开渲染该组件的对应路由时调用</span><br><span class="line">    // 与 `beforeRouteUpdate` 一样，它可以访问组件实例 `this`</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>​        <code>beforeRouteEnter</code> 守卫 <strong>不能</strong> 访问 <code>this</code>，因为守卫在导航确认前被调用，因此即将登场的新组件还没被创建。</p>
<p>​        不过，你可以通过传一个回调给 <code>next</code> 来访问组件实例。在导航被确认的时候执行回调，并且把组件实例作为回调方法的参数：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">beforeRouteEnter (to, from, next) &#123;</span><br><span class="line">  next(vm =&gt; &#123;</span><br><span class="line">    // 通过 `vm` 访问组件实例</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>​        注意 <code>beforeRouteEnter</code> 是支持给 <code>next</code> 传递回调的唯一守卫。对于 <code>beforeRouteUpdate</code> 和 <code>beforeRouteLeave</code> 来说，<code>this</code> 已经可用了，所以<em>不支持</em> 传递回调，因为没有必要了：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">beforeRouteUpdate (to, from) &#123;</span><br><span class="line">  // just use `this`</span><br><span class="line">  this.name = to.params.name</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>​        这个 <strong>离开守卫</strong> 通常用来预防用户在还未保存修改前突然离开。该导航可以通过返回 <code>false</code> 来取消。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">beforeRouteLeave (to, from) &#123;</span><br><span class="line">  const answer = window.confirm(&#x27;Do you really want to leave? you have unsaved changes!&#x27;)</span><br><span class="line">  if (!answer) return false</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="使用组合式-API"><a href="#使用组合式-API" class="headerlink" title="使用组合式 API"></a>使用组合式 API</h3><p>​        如果你正在使用<a target="_blank" rel="noopener" href="https://v3.vuejs.org/guide/composition-api-setup.html#setup">组合 API 和 <code>setup</code> 函数</a>来编写组件，你可以通过 <code>onBeforeRouteUpdate</code> 和 <code>onBeforeRouteLeave</code> 分别添加 update 和 leave 守卫。 请参考<a target="_blank" rel="noopener" href="https://router.vuejs.org/zh/guide/advanced/composition-api.html#%E5%AF%BC%E8%88%AA%E5%AE%88%E5%8D%AB">组合 API 部分</a>以获得更多细节。</p>
<h2 id="完整的导航解析流程"><a href="#完整的导航解析流程" class="headerlink" title="完整的导航解析流程"></a>完整的导航解析流程</h2><ul>
<li>导航被触发</li>
<li>在失活的组件里调用 <code>beforeRouteLeave</code> 守卫。</li>
<li>调用全局的 <code>beforeEach</code> 守卫。</li>
<li>在重用的组件里调用 <code>beforeRouteUpdate</code> 守卫(2.2+)。</li>
<li>在路由配置里调用 <code>beforeEnter</code>。</li>
<li>解析异步路由组件。</li>
<li>在被激活的组件里调用 <code>beforeRouteEnter</code>。</li>
<li>调用全局的 <code>beforeResolve</code> 守卫(2.5+)。</li>
<li>导航被确认。</li>
<li>调用全局的 <code>afterEach</code> 钩子。</li>
<li>触发 DOM 更新。</li>
<li>调用 <code>beforeRouteEnter</code> 守卫中传给 <code>next</code> 的回调函数，创建好的组件实例会作为回调函数的参数传入。</li>
</ul>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">触发导航，失活调用组件的routeleave，调用全局的beforeEach，重用组件调用routeUpdate，调用路由配置beforeEnter，调用routeEnter，调用全局beforeResolve，调用全局afterEach，调用routeEnter的next回调函数。</span><br></pre></td></tr></table></figure>



<h1 id="路由元信息"><a href="#路由元信息" class="headerlink" title="路由元信息"></a>路由元信息</h1><p>​        有时，你可能希望将任意信息附加到路由上，如过渡名称、谁可以访问路由等。这些事情可以通过接收属性对象的<code>meta</code>属性来实现，并且它可以在路由地址和导航守卫上都被访问到。定义路由的时候你可以这样配置 <code>meta</code> 字段：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">const routes = [</span><br><span class="line">  &#123;</span><br><span class="line">    path: &#x27;/posts&#x27;,</span><br><span class="line">    component: PostsLayout,</span><br><span class="line">    children: [</span><br><span class="line">      &#123;</span><br><span class="line">        path: &#x27;new&#x27;,</span><br><span class="line">        component: PostsNew,</span><br><span class="line">        // 只有经过身份验证的用户才能创建帖子</span><br><span class="line">        meta: &#123; requiresAuth: true &#125;</span><br><span class="line">      &#125;,</span><br><span class="line">      &#123;</span><br><span class="line">        path: &#x27;:id&#x27;,</span><br><span class="line">        component: PostsDetail</span><br><span class="line">        // 任何人都可以阅读文章</span><br><span class="line">        meta: &#123; requiresAuth: false &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    ]</span><br><span class="line">  &#125;</span><br><span class="line">]</span><br></pre></td></tr></table></figure>

<p>​        首先，我们称呼 <code>routes</code> 配置中的每个路由对象为 <strong>路由记录</strong>。路由记录可以是嵌套的，因此，当一个路由匹配成功后，它可能匹配多个路由记录。</p>
<p>​        例如，根据上面的路由配置，<code>/posts/new</code> 这个 URL 将会匹配父路由记录 (<code>path: &#39;/posts&#39;</code>) 以及子路由记录 (<code>path: &#39;new&#39;</code>)。</p>
<p>​        一个路由匹配到的所有路由记录会暴露为 <code>$route</code> 对象(还有在导航守卫中的路由对象)的<code>$route.matched</code> 数组。我们需要遍历这个数组来检查路由记录中的 <code>meta</code> 字段，但是 Vue Router 还为你提供了一个 <code>$route.meta</code> 方法，它是一个非递归合并<strong>所有 <code>meta</code></strong> 字段的（从父字段到子字段）的方法。这意味着你可以简单地写</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">router.beforeEach((to, from) =&gt; &#123;</span><br><span class="line">  // 而不是去检查每条路由记录</span><br><span class="line">  // to.matched.some(record =&gt; record.meta.requiresAuth)</span><br><span class="line">  if (to.meta.requiresAuth &amp;&amp; !auth.isLoggedIn()) &#123;</span><br><span class="line">    // 此路由需要授权，请检查是否已登录</span><br><span class="line">    // 如果没有，则重定向到登录页面</span><br><span class="line">    return &#123;</span><br><span class="line">      path: &#x27;/login&#x27;,</span><br><span class="line">      // 保存我们所在的位置，以便以后再来</span><br><span class="line">      query: &#123; redirect: to.fullPath &#125;,</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<p>​        matched 里面的值的path是一个路由定义的样子(/about/:id) 而不是实际的url路由值。</p>
<h2 id="TypeScript"><a href="#TypeScript" class="headerlink" title="TypeScript"></a>TypeScript</h2><p>​        可以通过扩展 <code>RouteMeta</code> 接口来输入 meta 字段：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">// typings.d.ts or router.ts</span><br><span class="line">import &#x27;vue-router&#x27;</span><br><span class="line"></span><br><span class="line">declare module &#x27;vue-router&#x27; &#123;</span><br><span class="line">  interface RouteMeta &#123;</span><br><span class="line">    // 是可选的</span><br><span class="line">    isAdmin?: boolean</span><br><span class="line">    // 每个路由都必须声明</span><br><span class="line">    requiresAuth: boolean</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h1 id="数据获取"><a href="#数据获取" class="headerlink" title="数据获取"></a>数据获取</h1><p>​        有时候，进入某个路由后，需要从服务器获取数据。例如，在渲染用户信息时，你需要从服务器获取用户的数据。我们可以通过两种方式来实现：</p>
<ul>
<li><strong>导航完成之后获取</strong>：先完成导航，然后在接下来的组件生命周期钩子中获取数据。在数据获取期间显示“加载中”之类的指示。</li>
<li><strong>导航完成之前获取</strong>：导航完成前，在路由进入的守卫中获取数据，在数据获取成功后执行导航。</li>
</ul>
<p>​        从技术角度讲，两种方式都不错 —— 就看你想要的用户体验是哪种。</p>
<h2 id="导航完成后获取数据"><a href="#导航完成后获取数据" class="headerlink" title="导航完成后获取数据"></a>导航完成后获取数据</h2><p>​        当你使用这种方式时，我们会马上导航和渲染组件，然后在组件的 created 钩子中获取数据。这让我们有机会在数据获取期间展示一个 loading 状态，还可以在不同视图间展示不同的 loading 状态。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;div class=&quot;post&quot;&gt;</span><br><span class="line">    &lt;div v-if=&quot;loading&quot; class=&quot;loading&quot;&gt;Loading...&lt;/div&gt;</span><br><span class="line"></span><br><span class="line">    &lt;div v-if=&quot;error&quot; class=&quot;error&quot;&gt;&#123;&#123; error &#125;&#125;&lt;/div&gt;</span><br><span class="line"></span><br><span class="line">    &lt;div v-if=&quot;post&quot; class=&quot;content&quot;&gt;</span><br><span class="line">      &lt;h2&gt;&#123;&#123; post.title &#125;&#125;&lt;/h2&gt;</span><br><span class="line">      &lt;p&gt;&#123;&#123; post.body &#125;&#125;&lt;/p&gt;</span><br><span class="line">    &lt;/div&gt;</span><br><span class="line">  &lt;/div&gt;</span><br><span class="line">&lt;/template&gt;</span><br></pre></td></tr></table></figure>

<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line">export default &#123;</span><br><span class="line">  data() &#123;</span><br><span class="line">    return &#123;</span><br><span class="line">      loading: false,</span><br><span class="line">      post: null,</span><br><span class="line">      error: null,</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  created() &#123;</span><br><span class="line">    // watch 路由的参数，以便再次获取数据</span><br><span class="line">    this.$watch(</span><br><span class="line">      () =&gt; this.$route.params,</span><br><span class="line">      () =&gt; &#123;</span><br><span class="line">        this.fetchData()</span><br><span class="line">      &#125;,</span><br><span class="line">      // 组件创建完后获取数据，</span><br><span class="line">      // 此时 data 已经被 observed 了</span><br><span class="line">      &#123; immediate: true &#125;</span><br><span class="line">    )</span><br><span class="line">  &#125;,</span><br><span class="line">  methods: &#123;</span><br><span class="line">    fetchData() &#123;</span><br><span class="line">      this.error = this.post = null</span><br><span class="line">      this.loading = true</span><br><span class="line">      // replace `getPost` with your data fetching util / API wrapper</span><br><span class="line">      // 用你的数据获取 util 或 API 替换 `getPost`</span><br><span class="line">      getPost(this.$route.params.id, (err, post) =&gt; &#123;</span><br><span class="line">        this.loading = false</span><br><span class="line">        if (err) &#123;</span><br><span class="line">          this.error = err.toString()</span><br><span class="line">        &#125; else &#123;</span><br><span class="line">          this.post = post</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;)</span><br><span class="line">    &#125;,</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>​        简单来说就是创建了 loading error post 三个状态，然后再created的时候创建监听（理由是创建的监听参数的变化，可以重复触发。否则在参数变化时使用的复用将不会触发改变。）使用 immediate 为true，立刻触发。再调用fetch方法。然后再进行调用时设置post，error为null，作用是避免复用的影响，设置loading为true，然后便是正常的获取数据并显示了。</p>
<h2 id="导航完成前获取数据"><a href="#导航完成前获取数据" class="headerlink" title="导航完成前获取数据"></a>导航完成前获取数据</h2><p>​        通过这种方式，我们在导航转入新的路由前获取数据。我们可以在接下来的组件的 <code>beforeRouteEnter</code> 守卫中获取数据，当数据获取成功后只调用 <code>next</code> 方法：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">export default &#123;</span><br><span class="line">  data() &#123;</span><br><span class="line">    return &#123;</span><br><span class="line">      post: null,</span><br><span class="line">      error: null,</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  beforeRouteEnter(to, from, next) &#123;</span><br><span class="line">    getPost(to.params.id, (err, post) =&gt; &#123;</span><br><span class="line">      next(vm =&gt; vm.setData(err, post))</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;,</span><br><span class="line">  // 路由改变前，组件就已经渲染完了</span><br><span class="line">  // 逻辑稍稍不同</span><br><span class="line">  async beforeRouteUpdate(to, from) &#123;</span><br><span class="line">    this.post = null</span><br><span class="line">    try &#123;</span><br><span class="line">      this.post = await getPost(to.params.id)</span><br><span class="line">    &#125; catch (error) &#123;</span><br><span class="line">      this.error = error.toString()</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>​        这个就是在 beforeRouteEnter里面调用了异步请求，然后再获取到数据之后将数据使用next回调进行调用。同时再beforeRouteUpdate进行更新时使用了es6的async 和 await方法。同时设置this.post为null，然后在调用getPost方法获取数据返回给post。</p>
<p>​        在为后面的视图获取数据时，用户会停留在当前的界面，因此建议在数据获取期间，显示一些进度条或者别的指示。如果数据获取失败，同样有必要展示一些全局的错误提醒。</p>
<h1 id="组合式API"><a href="#组合式API" class="headerlink" title="组合式API"></a>组合式API</h1><h2 id="在-setup-中访问路由和当前路由"><a href="#在-setup-中访问路由和当前路由" class="headerlink" title="在 setup 中访问路由和当前路由"></a>在 setup 中访问路由和当前路由</h2><p>​        因为我们在 <code>setup</code> 里面没有访问 <code>this</code>，所以我们不能再直接访问 <code>this.$router</code> 或 <code>this.$route</code>。作为替代，我们使用 <code>useRouter</code> 函数：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">import &#123; useRouter, useRoute &#125; from &#x27;vue-router&#x27;</span><br><span class="line"></span><br><span class="line">export default &#123;</span><br><span class="line">  setup() &#123;</span><br><span class="line">  	// useRouter 和 useRoute 是一个方法。返回一个route 和 router 的一个对象</span><br><span class="line">  	// route 是当前路由的信息， router 主要是原型的方法。和 全局路由信息。</span><br><span class="line">    const router = useRouter()</span><br><span class="line">    const route = useRoute()</span><br><span class="line"></span><br><span class="line">	// </span><br><span class="line">    function pushWithQuery(query) &#123;</span><br><span class="line">      router.push(&#123;</span><br><span class="line">        name: &#x27;search&#x27;,</span><br><span class="line">        query: &#123;</span><br><span class="line">          ...route.query,</span><br><span class="line">        &#125;,</span><br><span class="line">      &#125;)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>​        <code>route</code> 对象是一个响应式对象，所以它的任何属性都可以被监听，但你应该<strong>避免监听整个 <code>route</code></strong> 对象：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">import &#123; useRoute &#125; from &#x27;vue-router&#x27;</span><br><span class="line"></span><br><span class="line">export default &#123;</span><br><span class="line">  setup() &#123;</span><br><span class="line">    const route = useRoute()</span><br><span class="line">    const userData = ref()</span><br><span class="line"></span><br><span class="line">    // 当参数更改时获取用户信息</span><br><span class="line">    watch(</span><br><span class="line">      () =&gt; route.params,</span><br><span class="line">      async newParams =&gt; &#123;</span><br><span class="line">        userData.value = await fetchUser(newParams.id)</span><br><span class="line">      &#125;</span><br><span class="line">    )</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>​        请注意，在模板中我们仍然可以访问 <code>$router</code> 和 <code>$route</code>，所以不需要在 <code>setup</code> 中返回 <code>router</code> 或 <code>route</code>。</p>
<h2 id="导航守卫-1"><a href="#导航守卫-1" class="headerlink" title="导航守卫"></a>导航守卫</h2><p>​        </p>

    </div>

    
    
    

    <footer class="post-footer">
          <div class="post-tags">
              <a href="/tags/router/" rel="tag"># router</a>
          </div>

        

          <div class="post-nav">
            <div class="post-nav-item">
                <a href="/2022/02/07/router/router%E5%9F%BA%E7%A1%80/" rel="prev" title="router基础">
                  <i class="fa fa-chevron-left"></i> router基础
                </a>
            </div>
            <div class="post-nav-item">
                <a href="/2022/02/11/router/%E6%BA%90%E7%A0%81/router3%E6%BA%90%E7%A0%81/" rel="next" title="router3源码初学">
                  router3源码初学 <i class="fa fa-chevron-right"></i>
                </a>
            </div>
          </div>
    </footer>
  </article>
</div>






</div>
  </main>

  <footer class="footer">
    <div class="footer-inner">


<div class="copyright">
  &copy; 
  <span itemprop="copyrightYear">2023</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">tallgy</span>
</div>
  <div class="powered-by">由 <a href="https://hexo.io/" rel="noopener" target="_blank">Hexo</a> & <a href="https://theme-next.js.org/muse/" rel="noopener" target="_blank">NexT.Muse</a> 强力驱动
  </div>

    </div>
  </footer>

  
  <script src="https://cdn.jsdelivr.net/npm/animejs@3.2.1/lib/anime.min.js" integrity="sha256-XL2inqUJaslATFnHdJOi9GfQ60on8Wx1C2H8DYiN1xY=" crossorigin="anonymous"></script>
<script src="/js/comments.js"></script><script src="/js/utils.js"></script><script src="/js/motion.js"></script><script src="/js/schemes/muse.js"></script><script src="/js/next-boot.js"></script>

  





  





</body>
</html>
